package com.ctsi.commons.event;

import com.ctsi.commons.util.JsUtil;
import com.ctsi.commons.util.UtilValidate;
import com.ctsi.commons.util.async.TaskManagerHolder;
import com.ctsi.commons.util.async.TaskRun;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.Map;

/**
 * Observer 父类,提供同步异步的支持
 * 
 * @author zhangjw
 * 
 */
public abstract class AbstractObserver implements Observer, TaskRun, Serializable {
	private static final Logger log = LoggerFactory.getLogger(AbstractObserver.class);

	private String condition;

	private String name;

	private long waiteTime = 0;

	private boolean userDefSync = true;

	@Override
	public boolean isUserDefSync() {
		return userDefSync;
	}

	@Override
	public void setUserDefSync(boolean userDefSync) {
		this.userDefSync = userDefSync;
	}

	public long getWaiteTime() {
		return waiteTime;
	}

	public void setWaiteTime(long waiteTime) {
		this.waiteTime = waiteTime;
	}

	@Override
	public boolean isRun(BaseEvent o, Map<String, ?> context) {
		if (UtilValidate.isEmpty(condition)) {
			return runEvent(o, context);
		}
		log.debug("condition is \n{}", condition);
		Object result = JsUtil.eval(condition, (Map<String, Object>) context);
		if (result instanceof Boolean) {
			return ((Boolean) result).booleanValue();
		} else {
			if (result == null) {
				throw new RuntimeException("return value should boolean");
			} else {
				throw new RuntimeException("return value should boolean,but:" + result.getClass().getName());
			}
		}

	}

	private boolean run = true;

	public boolean isRun() {
		return run;
	}

	public void setRun(boolean run) {
		this.run = run;
	}

	protected boolean runEvent(BaseEvent o, Map<String, ?> context) {
		return run;
	}

	@Override
	public void setCondition(String con) {
		condition = con;

	}

	public boolean isSync() {

		return userDefSync;
	}

	@Override
	public Object run(Object[] args) {
		onEvent(args);
		return null;
	}

	public void setSync(boolean isSync) {
		this.userDefSync = isSync;

	}

	/**
	 * 第一个参数是BaseEvent,其他为传递参数
	 * 
	 * @param args
	 */
	public abstract void onEvent(Object[] args);

	@Override
	public void update(final BaseEvent o, Object... arg) throws NotRollbackExcetion {
		Object[] arrayArg;
		if (UtilValidate.isNotEmpty(arg)) {
			arrayArg = new Object[arg.length + 1];
			arrayArg[0] = o;
			System.arraycopy(arg, 0, arrayArg, 1, arg.length);
		}

		else {
			arrayArg = new Object[1];
			arrayArg[0] = o;
		}

		// List<Object> args=new ArrayList<Object>();
		// args.add(o);
		// for (Object tmp : arg) {
		// args.add(tmp);
		// }
		if (isSync()) {
			try {
				onEvent(arrayArg);
			} catch (NotRollbackExcetion e) {
				throw e;
			} catch (Throwable e) {
				if (catchException) {
					throw new NotRollbackExcetion(e);
				} else {
					throw new RuntimeException(e);
				}
			}
		} else {
			log.info("event {} is async  waiteTime :{}", name, waiteTime);
			TaskManagerHolder.getTaskManager().execute(this, arrayArg, waiteTime);
		}
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public void setName(String name) {
		this.name = name;
	}

	private String id;

	@Override
	public String getId() {
		return id;
	}

	@Override
	public void setId(String id) {
		this.id = id;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (!(obj instanceof Observer) || id == null) {
			return false;
		}
		return id.equals(((Observer) obj).getId());
	}

	@Override
	public int hashCode() {
		return id == null ? super.hashCode() : id.hashCode();
	}

	@Override
	public String toString() {
		return name == null ? this.id : name;
	}

	private boolean catchException = true;

	public boolean isCatchException() {
		return catchException;
	}

	public void setCatchException(boolean catchException) {
		this.catchException = catchException;
	}
}
